<?php
/* 
 * kernel/init.php
 * 
 * This code is distributed and used under the GNU GPL v2 License,
 * please, read file LICENSE, which is situated in root directory,
 * or in "LICENSE" directory with most acceptable translation for you
 * 
 * Main system architecrure object, basic initialization
 * 
 * Copyright (C) 2010, Taras Kudla
 * 
 * NOTE:
 * this file is major system object, without it everything will be unworkable,
 * and even, can damage your data. To prevent unspecated result, please,
 * keep this in original state :)
 * 
 *
 */

# checking for php version
if( strcmp("5.1.6",PHP_VERSION)>0 ){
	print "Gepard requires PHP version > 5.1.6 Your version is: ".PHP_VERSION;
	exit;
}
/*
 * Gepard constants area
 * ----------------------------------------------------------------------------
 * NOTE: For kernel objects, to prevent expceptional situations,
 *       we strongly recomend you to create defines here
 */

/*
 * Gepard Version
 */
define("_GEPARD_VERSION","0.1");
#
define("YES", true); // =)
define("NO", false);
/*
 * User groups by default
 */
define("_GROUP_ADMIN",1);
define("_GROUP_DEFAULT",2);
/*
 * Run modes defines
 */
define("_AJAX_RUNMODE", 1);     # ajax mode, all forms, action, etc. will be prepared for this in automatic mode
define("_HTML_RUNMODE", 0);     # using just html, without any dynamic actions by system
define("_CONSOLE_RUNMODE", 2);  # just console, usefull for small applications ( for example feed reader by cron, etc.)
/*
 * Access level defines (basic)
 * 
 * You can add any number of levels.
 * 
 * See documentation for more details.
 */
define("_FUNC_USER", 0);
define("_FUNC_ADMIN", 1); 
/*
 * Reaction on errors
 */
define("_STANDARD", 0); # standard reaction for error, nothing serious
define("_PARANOID", 1); # system will stop after any error
/*
 * Gepard Triggers types
 */
# on kernel objects calls
define("_TRIG_CALL",0);
# on module-method
define("_TRIG_EVENT",1);
define("_TRIG_ACTION",1);
# on signal
define("_TRIG_SIG",2);
define("_TRIG_MODCORECALL",3);
/*
 * Gepard Triggers Actions
 */
define("_TRIG_ONAFTER",0);
define("_TRIG_ONBEFORE",1);
define("_TRIG_FILTER",2);
/*
 * Environment layer defines
 */
define("_ENV_KERNEL", 0);   # kernel running at this moment
define("_ENV_MOD", 1);      # module method called, can use kernel throw api in this case
/*
 * Charsets, fully supported by all gepard objects
 */
define("_CHARSET_UTF8","UTF-8");
define("_CHARSET_CP1251","Windows-1251");
define("_CHARSET_KOI8R","KOI8-R");
define("_CHARSET_KOI8U","KOI8-U");
/*
 * Charset names for converting
 */
define("_CHARSET_CNMYSQL","mysql");
define("_CHARSET_CNPGSQL","pgsql");
define("_CHARSET_CNFIREBIRD","firebird");
define("_CHARSET_CNBROWSER","browser");
define("_CHARSET_CNLANGFILE","langfile");
/*
 * Some useful things
 */
define("_HASH_LENGTH", 20);         # hash length for actions
define("_SESSION_NAME", "gppses");  # default session name
define("_ARRAY",0);
define("_STRING",1);
define("_INT",2);
define("_FLOAT",3);
/*
 * Abstraction layers defines
 */
define("_DEFAULT_ABSTRACT_INIT", "gInit");
define("_DEFAULT_ABSTRACT_KERNEL", "gKernel");
define("_DEFAULT_ABSTRACT_MODULE", "gModule");
/*
 * Errors types
 */
define("_ERR_USER",10);
define("_ERR_NOTICE",20);
define("_ERR_WARNING",30);
define("_ERR_FATAL",40);
define("_ERR_CRIT",50);
/*
 * Basic log message levels
 */
define("_LOG_MESSAGE", 100);    # all messages
define("_LOG_NOTICE", 75);      # notice
define("_LOG_ERROR", 50);       # errors
define("_LOG_CRITICAL", 25);    # fatal errors
/*
 * System modules permission's
 */
define("_PERM_WRITESQL",0); # insert/update/delete system tables
define("_PERM_READSQL",1);  # reading from system tables
define("_PERM_WRITE",2);    # write to sys files
define("_PERM_ENV",3);      # changing environment information
define("_PERM_CALL",4);     # call another modules
define("_PERM_CHG",5);      # permissions changing
# default modules permissions
define("_PERM_DEFAULT","111111");
/*
 * Basic system service signals
 */
define("_SIG_INIT",0);  # system start
define("_SIG_DBO",1);   # database start
define("_SIG_CACHE",2); # caching engine start
define("_SIG_OPT",3);   # system global options load
define("_SIG_ERR",4);   # system on error signal
define("_SIG_CRIT",5);  # critical system event
define("_SIG_MEM",6);   # memory overflow
define("_SIG_ALRM",7);  # alarm
define("_SIG_REDIR",8); # http redirect signal
define("_SIG_MSG",9);   # system message
define("_SIG_HUP",10);  # system stop ( accuracy mode, for ex: redirection )
define("_SIG_CLSCON",11); # closing all alive connection's
# signals for using in modules or in intermodule communication
define("_SIG_USR1",20);	# user defined signal 1
define("_SIG_USR2",21); # user defined signal 2
define("_SIG_USR3",22); # user defined signal 3
define("_SIG_USR4",23); # user defined signal 4
define("_SIG_USR5",24); # user defined signal 5
define("_SIG_USR6",25); # user defined signal 6
define("_SIG_USR7",26); # user defined signal 7
define("_SIG_USR8",27); # user defined signal 8
define("_SIG_USR9",28); # user defined signal 9
define("_SIG_USR10",29); # user defined signal 10
define("_SIG_TERM",255); # system stop

//require_once 'linker.php';

class gInit {

    /**
     *
     * @var <type>
     */
    private $errors = null;

    private $error  = null;

    /**
     * List of native kernel objects
     *
     * @var <type>
     */
    private $Objects = array(
        "cms", "log", "dbo", "options","console", "user", "view", "i18n", "file",
        "api", "session", "tools", "cache","router","charset","document","encoding"
    );
    /**
     * Initialized kernel objects
     *
     * @var <type>
     */
    private $ObjectsLinks = array();
    /**
     * Dispatcher object
     *
     * @var <type>
     */
    private $dispatch = null;
    /**
     * Directory, where main files are situated
     *
     * @var <type>
     */
    private $Workdir = null;
    /**
     * Directory, where kernel is situated
     *
     * @var <type>
     */
    private $Kerneldir = null;  
    /**
     * Main Gepard configuration
     *
     * @var <type>
     */
    private $Configuration = array(
    	# basic url (not required)
    	"url" 		=> null,
    	# url suffix (not required)
    	"urlsuffix"	=> null,
    	# host system signature ( optional )
    	"hostsign"	=> null,
    	# main system run file
    	"runfile"	=> "index",
    	# how to run a system html|ajax|console
    	"runmode"	=> _HTML_RUNMODE,
    	# internal system/applcation name
    	"name"		=>	"appdefault",
    	# basic access level ( can be changed in amin panel)
    	"accesslevel"	=> _FUNC_USER,
    	# database engine configuration file
    	"dboconf"	=> null,
    	# persistent database connection
    	"dbopersistent" => true,
    	# use dbo data replication, see docs for more information
    	"dbodatareplication"=> NO,
    	# dbo tables prefix
    	"dbotablesprefix"=>null,
    	# caching engine configuration file
    	"cacheconf"	=> null,
    	# logs files directory
    	"logsdir"	=> "app/logs/",
    	# meessage when error generated ( not recomended when using as framework )
    	"messageonerror" => YES,
    	# throw new exception on error
    	"exceptiononerror"=> NO,
    	# directory where backups will store
    	"backupsdir"    => "app/backups/",
    	# where upload files should save
    	"uploadsdir"	=> "app/uploads/",
    	# url to upload files
    	"uploadsurl"    => "app/uploads/",
    	# temporary files directory
    	"tmpdir"        => "app/tmp/",
    	# timezone
    	"timezone"      => null,
    	# system configuration file ( not required)
    	"sysappconf"	=> "app/conf/app_default.php",
    	# templates directory in file system
    	"templatesdir"  => "view/templates/",
    	# tempaltes url routine
    	"templatesurl"	=> "view/templates/",
    	# templates engine
    	"tplengine"	=> "native",
    	# modules direcory
    	"modsdir"       => "modules/",
    	# modules url routine
    	"modsurl"       => "modules/",
        # application modules directory
        "appmodsdir"    => "app/modules/",
        # application modules url
        "appmodsurl"    => "app/modules/",
        # default timezone (when is empty in php.ini)
        "defaulttimezone"=>"Europe/Helsinki",
    	# library directory
    	"libdir"        => "library/",
    	# lib url
    	"liburl"        => "library/",
        #
        "protectedstore"=> "app/protectedstore/",
    	# url to jscorefiles
    	"jscoreurl"     => "js/",
    	# memory limit, in bytes, by default 10mb
    	"memorylimit"	=> 10485760,
    	# secure mode
    	"secure"	=> _PARANOID,
    	# logging enabled
    	"logtofile"	=> YES,
        # triggers support
        "usedispatcher"   => true,
    	# allow users multi access  ( when one login can work in different sessions )
    	"multiaccess"   => false,
    	# system language by default
    	"language"	=> "en",
    	# all supported system languages
    	"syslanguages"  => array("ru","en","ua"),
    	# url style
    	"urlroutermap"	=> "[f].php?[l]&[m]&[a]&[p]",
    	# html,xml,json api file
    	"apifile"	=> "api.php",
    	# basic system encoding, see docs for more details
    	"charset"	=> _CHARSET_UTF8,
        # setting for gzipped http response (if possible)
        "gziphttpresponse"=> false,
        # default session handler
        "sessionhandler"=>"database",
        # default session database handler
        "sessiondb"     =>"auto",
    	# session name
    	"sessionname"	=> _SESSION_NAME,
    	# profile enabled, true|false
        "useprofiler"   => true,
    	# debug enabled, true|false
    	"debug"		=> YES,
    	# view model by default
    	"viewmodel"	=> "default",
    	# should i connect to cache engine automatically
    	"usecache"	=> NO,
    	# should i connect to database automatically
    	"usedbo"	=> YES,
    	# time, after site will be not available for banned connections
    	"dennytimeout"  => 6000
    );
    /**
     * Time, when Gepard was started
     *
     * @var <type>
     */
    private $SystemStartTime = null;
    /**
     * Array of signals
     *
     * @var <type>
     */
    private $signals = array();
    /**
     * Initialized Gepard libraries
     *
     * @var <type>
     */
    private $libloaded = array();
    /**
     * Initialized Gepard modules
     * 
     * @var array
     */
    private $modloaded = array();
    
    /**
     * 
     *
     * @var <type>
     */
    private $triggercall = array();
    private $triggerevent = array();
    private $triggersig = array();
    private $triggermodcorecall = array();

    /**
     * Array where debug messages are stored
     *
     * @var <type>
     */
    private $DebugBuffer = array();
    /**
     * Maximum number of debug messages
     *
     * @var <type>
     */
    private $DebugBufferSize = 4096;    
    /*
     * System options states
     */
    private $optstates = array();
    private $memusage = 0;
    /**
     * Loaded Gepard kernel modules
     *
     * @var <type>
     */
    private $Loaded = array();
    private $ENV_LAYER = _ENV_KERNEL;
    private $ENV_CALLER = array(
        "ID" => null,"HASH"=>null, "NAME" => null, "MOD" => null, "MESSAGE" => null,"CALLSTACK"=>array(), "ERROR" => null, "ERROR_COUNT" => 0);
    private $Kernel =  _GEPARD_VERSION; # kernel version
    private $Version = _GEPARD_VERSION; # ready content management system version

    /*
     * System Initialization
     */
    function __construct()
    {
        #
      	$this->memusage = memory_get_usage();
      	$this->SystemStartTime = microtime(1);
        $this->setsighandler(_SIG_TERM,array(&$this,"stop") );
        $this->Workdir = dirname(__FILE__);
        $this->Kerneldir = $this->parseasdir($this->Workdir);
        $this->Workdir = preg_replace("/(core)/", "", $this->Workdir);
        $initimezone = ini_get("date.timezone");
        if( empty($initimezone)){
            date_default_timezone_set($this->Configuration["defaulttimezone"]);
        }
        # runmode checking
        if($this->isconsole() ){
        	$this->debug("init","Switching to console runmode");     	
        	$this->set("runmode",_CONSOLE_RUNMODE);
        }
        # runfile detection
        if( isset($_SERVER["SCRIPT_FILENAME"])){
        	$script = $_SERVER["SCRIPT_FILENAME"];
        	$script = str_replace(str_replace("\\","/",$this->Workdir),"",str_replace("\\","/",$script));
        	$script = preg_replace("/(.+)\.([A-z0-9_]{1,6})$/sU","$1",$script);
        	$this->debug("init","Trying to set runfile ($script)...Ok");
        	$this->set("runfile",$script);     	  		
        }
        require_once 'abstract/layer.php';
        require_once 'error.php';

        $this->dispatch = new gDispatcher($this);
        $this->errors   = new gError($this);
        $this->error    = $this->errors;
        # error handler signal
        $this->setsighandler(_SIG_ERR,array(&$this->errors,"create"));
        # message signal handler
        $this->setsighandler(_SIG_MSG,array(&$this->errors,"message"));
        #
        $this->setsighandler(_SIG_CLSCON,array(&$this,"closeallconnections"));
        # alarm signal handler
        $this->setsighandler(_SIG_ALRM,array(&$this->errors,"alarm"));
        /*
         * Seeking for configuration file
         */
        $sysfile = ( defined("_GEPARD_APPCONF"))?_GEPARD_APPCONF:$this->Configuration["sysappconf"];
        # checking for prefix
        if( !preg_match("/^([A-z]{1}\:)/",$sysfile)&& !preg_match("/^(\/{1})/",$sysfile) ){
            $sysfile = $this->Workdir.$sysfile;
        }
        if( is_file($sysfile) ){
            if( preg_match("/\.(php|ini)$/i",$sysfile,$tmp)){
                $filetype = strtolower($tmp[1]);
                if( $filetype=="php"){
                    $Gepard = & $this;
                    require_once($sysfile);
                } else {
                    # parsing as ini file
                    $data = parse_ini_file($sysfile,true);
                    //$this->htmlvardump($data);
                    # system parameters
                    if( array_key_exists("system",$data) && is_array($data["system"])){
                        foreach($data["system"] as $k=>$v){
                            if( array_key_exists($k,$this->Configuration)){
                                $this->Configuration[$k]=$v;
                            }
                        }
                    }
                    # database
                    if( array_key_exists("database",$data) && is_array($data["database"])){
                        foreach($data["database"] as $k=>$v){
                            if( !is_array($v)) continue;
                            $this->Configuration["dboconf"][$k]=$v;
                        }
                    }
                }
            } else {
                $this->error("init","Cannot detect system configuration file type, it must be: .php or .ini",_ERR_FATAL,__FILE__,__LINE__);
            }

        } else {
            $this->debug("INIT","System configuration file not found");
        }
        /*
         * Setting major system start signal
         */
        $this->setsighandler(_SIG_INIT,array(&$this,"start"));
    }
	
    function __destruct()
    {
    	$this->signal(_SIG_TERM);
    }

   /**
    * Helps to process dynamic objects linking architecture both with dispatcher
    * 
    * @param string $key    required object name
    * @return object
    */
    function __get($key)
    {
        # checking to prevent code execution in configuration file
        if( !$this->sighandler(_SIG_INIT)){
            return false;
        }
        $classname = "g".$key;
        # checking if object is allowed
        if (!in_array($key, $this->Objects) ){
            $this->error("INIT","Property '$key' not found",_ERR_NOTICE,__FILE__,__LINE__);
            return false;
        }
        $start = microtime(true);
        # checking if object was already loaded
        if($this->isloaded($key)) {
            # checking if module action running, adding to it's callstack
            if( $this->ENV_LAYER==_ENV_MOD){
                $this->ENV_CALLER["CALLSTACK"][]="kernel.".$key;
            }
            # non first object call
            if( $this->Configuration["usedispatcher"]){
                $this->dispatch->setstatecaller($key);
                return $this->dispatch;
            } else {
                return $this->ObjectsLinks[$key];
            }
        }
        $file = $this->Kerneldir.$key.".php";
        if( file_exists($file)){
            require_once($file);
        } else {
            $this->error("INIT","System object '$key' file not found",_ERR_FATAL,__FILE__,__LINE__);
            return null;
        }
        # first time object linking
        if (get_parent_class($classname) == _DEFAULT_ABSTRACT_KERNEL){
            $tmpObj = new $classname($this);
            $tmpObj->init();
            $this->ObjectsLinks[$key] = &$tmpObj;
        }
        $this->Loaded[] = $key;
        $this->debug("OBJECT LOADER", "Kernel object '" . $key . "' loaded");
        if( $this->Configuration["usedispatcher"]){
            $this->dispatch->setstatecaller($key);
            return $this->dispatch;
        } else {
             return $this->ObjectsLinks[$key];
        }
    }
 
    /**
     * Returns initialized kernel object
     *
     * @access public
     * @param string $name name of required object
     * @return gkernel
     */
    public function & getObject($name)
    {
        if( !array_key_exists($name,$this->ObjectsLinks)){
            $this->$name->void();
        }
        return $this->ObjectsLinks[$name];
    }

    /**
     * Returns statistics about all called objects, etc.
     *
     * @return array
     * @see gdispatcher::getDispatchTrace();
     */
    public function getKernelTrace()
    {
        if( !$this->Configuration["usedispatcher"]){
            $this->error("init","Cannot get kernel calls trace, dispatcher is disabled",_ERR_WARNING);
            return false;
        }
        return $this->dispatch->getDispatchTrace();
    }
    /**
     * Returns information about what is executing in current time
     * at a global layer
     *
     * @return 
     */
    public function getExecutionState()
    {
        return ($this->getenvlayer().":".$this->getenvcaller("mod").":".$this->getenvcaller("name"));
    }

    /*
     * Triggers engine
     *
     * NOTE: Some of triggers types works only with enabled dispatcher
     *
     * Triggers internal names:
     *  _TRIG_CALL:
     * array("object"=>"kernel_object_name","method"=>"method_name")
     * _TRIG_MODCORECALL:
     * array("module"=>"module_name","action"=>"module_method","object"=>"kernel_object_name","method"=>"ko_method_name")
     *
     */

    /**
     * Creates Gepard trigger (filter)
     *
     * @param constant  $type           trigger (filter) type
     * @param constant  $actiontype     trigger (filter) action type
     * @param array     $on             event data
     * @param object    $handler        handler, usually array($class,$methodname)
     * @param array     $handlerparams  handler params, usually array(...)
     * @return mixed                    false or trigger name
     */
    public function createtrigger($type,$actiontype,$on,$handler,$handlerparams=null)
    {
        if( !is_array($handlerparams)){
            $handlerparams=array();
        }
        /*
         * Checking handler compatibility
         */
        if( is_array($handler) && count($handler)>1){
            list($class,$method) = $handler;
            if( !is_object($class)){
                $this->error("createtrigger","Cannot create trigger, given handler is not an object",_ERR_FATAL,__FILE__,__LINE__);
                return false;
            }
            if(!method_exists($class,$method)){
                $this->error("createtrigger","Cannot create trigger, given handler obcjet method '$method' does not exist",_ERR_FATAL,__FILE__,__LINE__);
                return false;
            }
        } else {
            if( !function_exists($handler)){
                $this->error("createtrigger","Given function '$handler' does not exist",_ERR_FATAL,__FILE__,__LINE__);
                return false;
            }
        }

        # Creating trigger by type
        switch($type){
            case _TRIG_CALL:
                $name = $on["object"].":".$on["method"];
                $this->triggercall[$name] = array("handler"=>$handler,"ontype"=>$actiontype,"handlerparams"=>$handlerparams);
            break;
            case _TRIG_MODCORECALL:
                $name = $on["module"].":".$on["action"].":".$on["object"].":".$on.":".$on["method"];
                $this->triggermodcorecall[$name] = array("handler"=>$handler,"ontype"=>$actiontype,"handlerparams"=>$handlerparams);
            break;
            case _TRIG_ACTION:
            case _TRIG_EVENT:
                $name = $on["module"].":".$on["action"];
                $this->triggermodcorecall[$name] = array("handler"=>$handler,"ontype"=>$actiontype,"handlerparams"=>$handlerparams);
            break;
            case _TRIG_SIG:
                $name = $on["signal"];
                $this->triggermodcorecall[$name] = array("handler"=>$handler,"ontype"=>$actiontype,"handlerparams"=>$handlerparams);
            break;
        }
        return $name;
    }

    /**
     * TODO:
     *
     * Processing Gepard trigger (filter) call by event
     * NOTE: function is for internal use
     *
     * @param constant  $type           trigger (filter) type
     * @param constant  $actiontype     trigger (filter) action type
     * @param array     $on             event name
     *
     * @return mixed
     */
    public function calltrigger($type,$actiontype,$on)
    {
        switch($type){
            case _TRIG_CALL:
                $name = $on["object"].":".$on["method"];
                if(array_key_exists($name, $this->triggercall)){
                    $trigger = $this->triggercall[$name];
                    $handler = $trigger["handler"];
                    if( is_array($handler)){
                        list($class,$method) = $handler;
                        $call = array(&$class,$method);
                    } else {
                        $call = $handler;
                    }
                    if( $actiontype==_TRIG_ONBEFORE && $trigger["ontype"]==_TRIG_ONBEFORE ){
                        call_user_func_array($call,$trigger["handlerparams"]);
                    }
                    if( $actiontype==_TRIG_ONAFTER && $trigger["ontype"]==_TRIG_ONAFTER ){
                        call_user_func_array($call,$trigger["handlerparams"]);
                    }
                }
            break;
            case _TRIG_MODCORECALL:
                $name = $on["module"].":".$on["action"].":".$on["object"].":".$on.":".$on["method"];
                if(array_key_exists($name, $this->triggermodcorecall)){
                    $trigger = $this->triggermodcorecall[$name];
                    $handler = $trigger["handler"];
                    if( is_array($handler)){
                        list($class,$method) = $handler;
                        $call = array(&$class,$method);
                    } else {
                        $call = $handler;
                    }
                    if( $actiontype==_TRIG_ONBEFORE && $trigger["ontype"]==_TRIG_ONBEFORE ){
                        call_user_func_array($call,$trigger["handlerparams"]);
                    }
                    if( $actiontype==_TRIG_ONAFTER && $trigger["ontype"]==_TRIG_ONAFTER ){
                        call_user_func_array($call,$trigger["handlerparams"]);
                    }
                }
            break;
            case _TRIG_ACTION:
            case _TRIG_EVENT:
                
            break;
            case _TRIG_SIG:

            break;
        }
    }

    /**
     * Gepard core start, handler for signal _SIG_INIT
     *
     * @return boolean
     */
    public function start()
    {
        # 
      	if( $this->sigcalled(_SIG_INIT)){
      		return false;
      	}
      	if($this->isconsole() ){     	
        	$this->set("runmode",_CONSOLE_RUNMODE);
        }
        $StartPoint = microtime(1);
        preg_match("/^(?:(http|https):\/\/)?([^\/]+)(.*)/i", $this->get("url"), $tmp);
        $this->UrlSuffix = isset($tmp[3]) ? $tmp[3] : "/";
        $totalInitTime = round((microtime(1) - $StartPoint), 4);
        $this->signals[_SIG_INIT]["called"] = true;
        # Database engine start
        if ( $this->Configuration["usedbo"] ){
        	$this->dbo->connect();
        }       
        # Cache engine start
        if ($this->Configuration["usecache"] ){
            $this->cache->connect();
        }        
	$this->debug("INIT","System initialization");
        return true;
    }

    /**
     * One way string encode
     *
     * @param string $str
     * @return string
     */
    public function encodeString($str)
    {
        $str = md5($str);
        $salt = substr($str, 5, 9);
        $str = substr(md5($salt), 5, 2).$str.substr(md5($salt), 0, 5);
        return strtoupper($str);
    }

    /**
     * Replace denied characters, string in requested string
     *
     * @param string    $var        string to filter
     * @param array     $allowed    array of allowed characters
     * @return string
     */
    public function escapeString($var,$allowed=null)
    {
    	/*
    	 * 
    	 */
        $replaces = array(">"=>"&gt;","<"=>"&lt;",'\"'=>"&quot;","\""=>"&quot;","\'"=>"&#039;","'"=>"&#039;","{"=>"&#123;","}"=>"&#125;");        
        if( is_array($allowed)){
        	foreach($allowed as $k=>$v){
        		if(array_key_exists($v,$replaces))unset($replaces[$v]);
			}
		}
        $var = str_replace(array_keys($replaces),array_values($replaces),$var);
      	return $var;
    }

    /**
     * Escaping POST data for denied characters
     *
     * @return array
     */
    public function escapePOST()
    {
        $a = array();
        foreach (func_get_args() as $k => $v){
            $a[] = $this->escapeString($_POST[$v]);
        }
        return $a;
    }

    /**
     * Escaping array data for denied characters
     *
     * @return list
     */
    public function escapeList()
    {
        $a = array();
        foreach (func_get_args() as $k => $v){
            $a[] = $this->escapeString($v);
        }
        return $a;
    }

    /**
     * Returns initialized required library object
     *
     * @param string    $name       library object name
     * @param array     $parameters parameters for object
     * @return object
     */
    public function libload($name,$parameters=null)
    {
        $file=$this->parseasdir($this->get("libdir"))."lib.".$name.".php";
        if(file_exists($file)){
            require_once($file);
            if( class_exists($name,false) ){
            	if(get_parent_class($name)=="library"){
            		$libobj = new $name($this);
            		# checking for input parameters            		
            		if( !is_array($parameters))
            			$parameters=array();
            		call_user_func_array(array(&$libobj,"init"),$parameters);
            		$libobj->init();
            		return $libobj;
            	}
            } else {
            	$this->error("LIB LOADER","Cannot found class '$name' in library file",_ERR_FATAL,__FILE__,__LINE__);
            }
            $this->libloaded[]=$name;        
        }
    }

    /**
     * Checks whether such library was loaded
     *
     * @param string $name  library object name
     * @return boolean
     */
    public function islibloaded($name)
    {
    	return in_array($name,$this->libloaded);
    }

    /**
     * Checks whether such library object exists
     * @param string $name  library object name
     * @return boolean
     */
    public function libexists($name)
    {
    	$file=$this->parseasdir($this->get("libdir"))."lib.".$name.".php";
    	return file_exists($file);
    }
	
    /**
     *  Sets handler for Gepard signal
     *
     * @param constant   $signo     signal type
     * @param array      $handler   signal handler, usually array(&$object,$methodname)
     * @return boolean
     */
    public function setsighandler($signo,$handler)
    {
    	# 
    	if( $this->ENV_LAYER==_ENV_MOD && ( $signo<20 || $signo>30 ) ){
    		$this->error("INIT","Signal '$signo' is reserved for system handler",_ERR_NOTICE,__FILE__,__LINE__);
    		return false;
    	} else if( isset($this->signals[$signo]) ){
    		$this->error("INIT","Signal '$signo' have a handler already",_ERR_NOTICE,__FILE__,__LINE__);
    		return false;
    	} else if ( !is_array($handler) || !is_object($handler[0]) ){
    		$this->error("INIT","Signal '$signo' handler definition is incorrect",_ERR_NOTICE,__FILE__,__LINE__);
    		return false;    		
    	} 
    	$this->signals[$signo] = array("handler"=>$handler,"called"=>false);
    	$this->Debug("INIT","Handler for signal '$signo' ");
    	return true;
    }
    
    /**
     * Causes the signal handler
     *
     * @param contant       $signo          signal type
     * @param array         $parameters     data for signal handler
     * @return boolean
     */
    public function signal( $signo,$parameters = array() )
    {
        if( !isset($this->signals[$signo]) ){
    		$this->error("INIT","Cannot find handler for a signal '$signo' ",_ERR_NOTICE,__FILE__,__LINE__);
    		return false;
    	}
    	list($class,$method) = $this->signals[$signo]["handler"];
    	call_user_func_array(array(&$class,$method),$parameters);
    	$this->signals[$signo]["called"]=true;
        return true;
    }
    
    /**
     * Checks whether signal was called
     *
     * @param constant $signo   signal type
     * @return boolean
     */
    public function sigcalled( $signo )
    {
    	return isset($this->signals[$signo])?$this->signals[$signo]["called"]:false;
    }
    /**
     * Checks whether signal has handler
     *
     * @param @param constant $signo   signal type
     * @return boolean
     */
    public function sighandler($signo)
    {
    	return array_key_exists($signo,$this->signals);
    }

    /**
     * Checks whether requested fields exists in POST data
     * request example: ...checkPOST("var1","var2",...)
     *
     * @return boolean
     */
    public function checkPOST()
    {
        foreach (func_get_args() as $k => $v){
            if (!isset($_POST[$v]))
            return false;
        }
        return true;
    }

    /**
     * Checks whether requested fields exists in GET data
     * request example: ...checkGET("var1","var2",...)
     *
     * @return boolean
     */
    public function checkGET()
    {
        foreach (func_get_args() as $k => $v){
            if (!isset($_GET[$v]))
            return false;
        }
        return true;
    }

    /**
     * Puts data into debug buffer
     *
     * @param string $object    object name
     * @param string $string    message
     * @return boolean
     */
    public function Debug($object, $string = null)
    {
      	if( $this->Configuration["debug"] )
        $this->DebugBuffer[] = array( $object,str_replace($this->path(),"",$string) );
        return true;
    }
   /**
    * Gets debugger data by type
    *
    * @param contant $return    return type, string or array
    * @return string
    */
    public function &GetDebug($return=_ARRAY)
    {
      	if( $return == _STRING){
      		$buf = null;
      		foreach( $this->DebugBuffer as $k=>&$v){
      			$buf.=join(" | ",$v)."\n";}
      		return $buf;
      	}      
        return $this->DebugBuffer;
      }
      
   /**
     * Sets Gepard configuration option value (state)
     *
     * @param string $key       Gepard configuration option name
     * @param mixed  $state     value
     */
    public function setstate($key,$state)
    {
        if( array_key_exists($key,$this->Configuration)){
            $current = $this->Configuration[$key];
            # trying to set new state
            $this->set($key,$state);
            # trying to save old state
            $this->optstates[$key]=$current;
        }
    }
    /**
     * Restores last conf option state
     *
     * @param string $key   Gepard configuration option name
     */
    public function restorestate($key)
    {
        if( array_key_exists($key,$this->optstates)){
            $oldstate = $this->optstates[$key];
            $this->set($key,$oldstate);
        }
    }

      /**
       * Sets value for system configuration item
       *
       * @param string  $key        Gepard configuration option name
       * @param mixed   $value      value
       * @return boolean
       */
    public function set($key,$value=null)
    {
      	if( !in_array($key,$this->Configuration) ){
      		$this->error("INIT","System parameter '$key' not found",_ERR_NOTICE,__FILE__,__LINE__);
      		return false;
      	}
      	$key = strtolower($key);
    	# specific for language
    	if( $key == "language" || $key=="runmode" || $key=="exceptiononerror"){
    		$this->Configuration[$key]=$value;
    		return false;
    	}
    	if( $this->sigcalled(_SIG_INIT) ){
    		$this->error("INIT","Cannot set system parameters ('$key') after signal _SIG_INIT(init->start method)",_ERR_NOTICE,__FILE__,__LINE__);
    		return false;
    	}
    	# all options, cannot be changed after _SIG_INIT
    	if( array_key_exists($key,$this->Configuration)){
    		$this->Configuration[$key] = $value;
    	}
    	return true;
    }

      /**
       * Gets value of system configuration item
       *
       * @param string  $key        Gepard configuration option name
       * @return mixed
       */
    public function get($key)
    {
    	if( ($key=="dboconf" || $key=="cacheconf") && $this->ENV_LAYER==_ENV_MOD && $this->ENV_CALLER["MOD"]!="sys" ){
    		$this->error("INIT","Cannot return dbo or cache parameters when module action is running",_ERR_NOTICE,__FILE__,__LINE__);
    	}    	
    	# getting system parameters
    	if( array_key_exists($key,$this->Configuration) ){
    		return $this->Configuration[$key];
    	}
    	return false;
    }

    /**
     * Detects time elapsed from system start
     *
     * @return float
     */
    public function runtimepoint()
    {
        return round( (microtime(true)-$this->SystemStartTime) ,4);
    }

    /**
     * Clears runtime Gepard environment
     *
     * @return boolean
     */
    public function envclear()
    {
    	$this->ENV_LAYER = _ENV_KERNEL;
    	$this->ENV_CALLER["ID"] 		 = null;
    	$this->ENV_CALLER["HASH"]		 = null;
    	$this->ENV_CALLER["NAME"] 		 = null;
    	$this->ENV_CALLER["MOD"] 		 = null;
    	$this->ENV_CALLER["MESSAGE"] 	 = null;
    	$this->ENV_CALLER["ERROR"] 		 = null;
    	$this->ENV_CALLER["ERROR_COUNT"] = 0;
    	$this->ENV_CALLER["CALLSTACK"] 	 = array();
    	return true;
    }

    /**
     * Returns requested module object
     *
     * @param string $name      Module name
     * @return object
     */
    public function callmodule($name)
    {
        $path = $this->parseasdir($this->Configuration["modsdir"]);
        $appmodsfile = $this->parseasdir($this->Configuration["appmodsdir"]).$name."/mod.".$name.".php";
	$file = $path.$name."/mod." . $name . ".php";
	if (array_key_exists($name,$this->modloaded) && is_object($this->modloaded[$name]["object"]) && get_class($this->modloaded[$name]["object"]) == "mod_".$name){
            $object = & $this->modloaded[$name]["object"];
            return $object;
        } else {
            if( !file_exists($file)){
                if( !file_exists($appmodsfile)){
                    $this->error("init", "Cannot find module '" . $name . "'",_ERR_FATAL,__FILE__,__LINE__);
                    return false;
                } else {
                    $file = $appmodsfile;
                    // module is thrd-party
                    //array_push($this->appmodules, $name);
                }
            }
            require_once($file);
            $classname = "mod_" . $name;
            if (get_parent_class($classname) == _DEFAULT_ABSTRACT_MODULE){
            # loading module for first time
            # switching to custom errors handling
            $this->setstate("exceptiononerror", true);
            try {
                $data = $this->dbo->select("modules","permissions","where modname='$name'",_RESULT_SINGLE);
                if( !is_string($data)){
                    $data=false;
                }
            } catch ( GepardException $e){
                print $e->getMessage();
                $data=false;
            }
            $this->restorestate("exceptiononerror");
            if( is_bool($data) ){
                /*
                 * FIXME: default or full permissions, i don't know what is better
                 */
                $permissions=array(_PERM_WRITESQL=>true,_PERM_READSQL=>true,_PERM_WRITE=>true,_PERM_ENV=>true,_PERM_CHG=>true,_PERM_CALL=>true);
            } else {
                if( empty($data)){
                    $data=_PERM_DEFAULT;
                }
                $permissions=array(
                _PERM_WRITESQL=>isset($data[0])?(int)$data[0]:false,
                _PERM_READSQL=>isset($data[1])?(int)$data[1]:false,
                _PERM_WRITE=>isset($data[2])?(int)$data[2]:false,
                _PERM_ENV=>isset($data[3])?(int)$data[3]:false,
                _PERM_CALL=>isset($data[4])?(int)$data[4]:false,
                _PERM_CHG=>isset($data[5])?(int)$data[5]:false);
            }
            $this->modloaded[$name] = array("object"=>null,"permissions"=>null,"3rdparty"=>false);
            $this->modloaded[$name]["permissions"] = $permissions;
            $this->modloaded[$name]["object"] = new $classname($this);
            $this->modloaded[$name]["object"]->init();
            return $this->modloaded[$name]["object"];
            } else {
                $this->error("callmodule","Module '$classname' format is unsupported",_ERR_NOTICE,__FILE__,__LINE__);
            }
            $this->debug("callmodule","Module '$name' loaded in ".round(microtime(1)-$time,6)." sec");
        }
        return ;
    }
    /**
     * Sets Gepard runtime environement layer
     *
     * @param constant $layerno
     * @return boolean
     */
    public function setenvlayer($layerno)
    {
	$this->ENV_LAYER = $layerno;
    	return true;
    }
    /**
     *
     * @param string $adapterType
     * @param string $adapterName
     * @return boolean
     */
    public function loadAdapter($adapterType,$adapterName)
    {
        $firstName = "";
        $adapterPath = "";
        switch($adapterType){
            case "database":
                $firstName = "db";
                $adapterPath = "database";
                break;
            case "session":
                $firstName = "sess";
                $adapterPath = "session";
                break;
            case "view":
                $adapterPath = "view";
                $firstName = "engine";
                break;
        }
        $file = $this->corepath()."/adapters/$adapterPath/$firstName.$adapterName.php";
        if(file_exists($file)){
            include_once $file;
            return true;
        } else {
            return false;
        }
    }


    /**
     * Sets Gepard runtime enviroment caller
     *
     * @param array $callerdata     Information about caller
     */
    public function setenvcaller(array $callerdata)
    {
    	$this->ENV_CALLER = $callerdata;
    }

    /**
     * Updates Gepard runtime environemnt caller
     *
     * @param string $key       Key name
     * @param string $value     Key value
     * @return boolean
     */
    public function updateenvcaller($key,$value=null)
    {
    	$key=strtoupper($key);
    	if( array_key_exists($key,$this->ENV_CALLER)){
    		$this->ENV_CALLER[$key] = $value;
    	}
    	return true;
    }

    /**
     * Gets Gepard runtime environemnt layer
     *
     * @return integer
     */
    public function getenvlayer()
    {
    	
    	return $this->ENV_LAYER;	
    }

    /**
     * Gets Gepard runtime environment caller
     *
     * @param <type> $key
     * @return <type>
     */
    public function getenvcaller($key=null)
    {
    	
    	if($key!=null && array_key_exists(strtoupper($key),$this->ENV_CALLER) ){
    		return $this->ENV_CALLER[strtoupper($key)];
    	}
    	return $this->ENV_CALLER;
    }

    /**
     * Returns current Gepard working directory
     *
     * @return string
     */
    public function path()
    {
    	return $this->Workdir;
    }

    /**
     * Returs current Gepard kernel directory
     *
     * @return string
     */
    public function corepath()
    {
    	return $this->Kerneldir;
    }

    /**
     * Returs current Gepard kernel directory
     *
     * @return string
     */
    public function kernelpath()
    {
    	return $this->Kerneldir;
    }

    /**
     * Returns Gepard api file path
     *
     * @return string
     */
    public function apifile()
    {
    	return $this->Configuration["apifile"];
    }

    /**
     * Returns Gepard url
     *
     * @return string
     */
    public function url()
    {
    	return $this->Configuration["url"];
    }

    /**
     * Returns Gepard global view model (view template name)
     *
     * @return string
     */
    public function GetViewModel()
    {
    	return $this->Configuration["viewmodel"];
    }
     /**
     * Returns Gepard global view model (view template name)
     *
     * @return string
     */
    public function viewmodel()
    {
    	return $this->Configuration["viewmodel"];
    }

    /**
     * Returns current PHP memory usage
     *
     * @return integer
     */
    public function GetMemoryUsage()
    {
    	return memory_get_usage();
    }

    /**
     * Returns current PHP memory usage
     *
     * @return integer
     */
    public function memusage()
    {
    	return memory_get_usage();    
    }
    /**
     * Returns Gepard UIs default language
     *
     * @return string
     */
    public function GetLanguage()
    {
    
    	return $this->Configuration["language"];
    }
    /**
     * Returns Gepard UIs default language
     *
     * @return string
     */
    public function language()
    {
    	return $this->Configuration["language"];
    }
    /**
     * Returns Gepard UIs supported languages
     *
     * @return string
     */
    public function GetSysLanguages()
    {
    	
    	return $this->Configuration["syslanguages"];
    }
     /**
     * Returns Gepard UIs supported languages
     *
     * @return string
     */
    public function syslanguages()
    {
        return $this->Configuration["syslanguages"];
    }

    /**
     * Returns Gepard run type
     *
     * @return string
     */
    public function runmode()
    {
    	return $this->Configuration["runmode"];
    }

    /**
     * Returns value how url's are parsed
     *
     * @return string
     */
    public function geturlroutermap()
    {
    	return $this->Configuration["urlroutermap"];
    }
    /**
     * Returns current users access level
     *
     * @return integer
     */
    public function accesslevel()
    {
    	return $this->Configuration["accesslevel"];	
    }    
     /**
     * Returns value how url's are parsed
     *
     * @return string
     */
    public function urlroutermap()
    {
    	return $this->Configuration["urlroutermap"];
    }
    /**
     * Returns current users access level
     *
     * @return integer
     */
    public function GetUserAccessLevel()
    {
    	
    	return $this->Configuration["accesslevel"];
    }
    /**
     * Returns current users access level
     *
     * @return integer
     */
    public function useraccesslevel()
    {
    	return $this->Configuration["accesslevel"];
    }

    /**
     * Sets Gepard UI's language
     *
     * @param string $language      Language name
     * @return boolean
     */
    public function setLanguage($language)
    {
    	if(!in_array($language,$this->SysLanguages) ){
    		$this->error("INIT","Language '$language' is unsupported",_ERR_NOTICE,__FILE__,__LINE__);
    		return false;
    	} else $this->set("language",$language);
    	return true;
    }
    
    /**
     * Returns current Gepard system characters set
     *
     * @return string
     */
    public function GetCharset()
    {
        return $this->Configuration["charset"];
    }
    /**
     * Returns current Gepard system characters set
     * 
     * @return string
     */
    public function charset()
    {
    	return $this->Configuration["charset"];    
    }
    /**
     * Returns current Gepard version
     *
     * @return string
     */
    public function GetVersion()
    {
    	return $this->Version;
    }
    /**
     * Returns current Gepard version
     *
     * @return string
     */
    public function version()
    {
        return $this->Version;
    }
    
    
    public function GetKernelVersion()
    {
    	return $this->Kernel;
    }
    
    public function GetUrl()
    {
    	return $this->Url;
    }

    /**
     * Checks whether kernel object with name $objname was loaded
     *
     * @param string $objname   Gepard kernel object name
     * @return boolean
     */
    public function isloaded($objname)
    {
    	return in_array($objname,$this->Loaded);   	
    }
    
    /**
     * Creates a valuable path to Gepard config file from the specified value
     *
     * @param string $val
     * @return string
     */
    public function parseconfasfile($key)
    {
        $val=$this->get($key);
        if( !preg_match("/^([A-z]{1}\:)/",$val)&& !preg_match("/^(\/{1})/",$val) ){
            $val = $this->Workdir.$val;
        }
        return $val;
    }

    /**
     * Creates a valuable system path from the specified value
     *
     * @param string $val
     * @return string
     */
    public function parsepathtosys($val)
    {
        if( !preg_match("/^([A-z]{1}\:)/",$val)&& !preg_match("/^(\/{1})/",$val) ){
            $val = $this->Workdir.$val;
        }
        return $val;
    }

    /**
     * Creates a valuable path from the specified value
     *
     * @param string $val
     * @return string
     */
    public function parseasdir($val)
    {
    	$val = $this->parsepathtosys($val);
    	$ch=$val[strlen($val)-1];
    	if( $ch=="/" || $ch=="\\" )
            return $val;
    	else 
            return $val."/";
    }

    /**
     * Creates a valuable Gepard link from the specified text
     * 
     * @param string $val
     * @return string 
     */
    public function parseasurl($val)
    {
    	if( !preg_match("/^(http|https|\.\.|\.|\/)/",$val)){
    		$val = $this->get("url").$val;
    	}
    	$ch=$val[strlen($val)-1];
    	if( $ch=="/" || $ch=="\\" )
            return $val;
    	else 
            return $val."/";
    }    
    
    /**
     * Nice var_dump :)
     *
     * @param <type> $var
     * @return <type> 
     */
    public function htmlvardump(&$var)
    {
        if( $this->isconsole()){
            print_r($var);
            return;
        }
    	print "<pre>Html dump of variable :\n";
    	print_r($var);
    	print "</pre>";
    }
    
    /**
     * Creates a message
     * 
     * @param string $message
     * @return string
     */
    public function message($message)
    {
    	return $this->errors->message($message);
    }   

    /**
     * Simplifies error creating
     *
     * @see gerrors:create()
     *
     * @param <type> $source
     * @param <type> $description
     * @param <type> $type
     * @param <type> $file
     * @param <type> $line
     * @return <type> 
     */
    public function error($source,$description=null,$type=_ERR_USER,$file=null,$line=null)
    {
    	return $this->errors->create($source,$description,$type,$file,$line);
    }

    /**
     * HTTP Redirect on specified url, or by Gepard ACL's
     *
     * @param string $alias
     * @param string $params
     */
    public function redirect($alias=null,$params=null)
    {
    	$this->cms->sendHeader($alias,$params);
    }
    
    /**
     * Closes all alive connections (with db's, sessions, etc.)
     */
    public function closeallconnections()
    {
        if($this->isloaded("session"))
            $this->session->close();
        if($this->isloaded("cache"))
            $this->cache->disconnect();
        if($this->isloaded("dbo"))
            $this->dbo->disconnect();
        return true;
    }
    /**
     * Stops Gepard execution
     *
     * @return null
     */
    public function stop()
    {
    	if( $this->sigcalled(_SIG_TERM)){
            return false;
        }
    	if( !$this->sigcalled(_SIG_CLSCON)){
            $this->signal(_SIG_CLSCON);
        }
        $this->Debug("LAST","System stopped.");
        exit;
    }
    /**
     * Stops Gepard execution
     *
     * @return null
     */
    public function shutdown()
    {
        return $this->stop();
    }

    /**
     * Checks whether Gepard can be runned on current host environment
     * 
     * @return boolean
     */
    public function evaluate()
    {
    	$message = null;
    	$result  = true;
    	if(!isset($_SERVER["REQUEST_URI"])){
    		$message = "\$_SERVER[REQUEST_URL] required (not neccessary)";	
    	}
    	if( !isset($_COOKIE)){
    		$message = "\$_COOKIE required (not neccessary)";
    		$result  = false;
    	}   	
    	if ( !extension_loaded("gd") ){
    		$message = "PHP extension \"gd\" required";
    		$result  = false;
    	}
    	if ( !extension_loaded("zlib")){
    		$message = "PHP extension \"zlib\" required";
    		$result  = false;
    	}
    	if ( !extension_loaded("mbstring")){
    		$message = "PHP extension \"mbstring\" required";
    		$result	 = false;
    	}
    	if( !is_writable($this->GetConfigurationFile("logs"))){
    		$message = "Logs directory should be writable";
    		$result	 = false;
    	}
    	return array($message,$result);
    }    

    /**
     * Checks whether Gepard is running under PHP CLI
     *
     * @return boolean
     */
    public function isconsole()
    {
    	return (strcmp(strtolower(substr(PHP_SAPI,0,3)),"cli")==0)?true:false;
    }

    /**
     * 
     * @return <type> 
     */
    function  __toString()
    {
        return "This application is running under the Gepard php code, version: ".$this->Version."\n";
    }

}
$Gepard = new gInit();